/**
 * Created with JetBrains PhpStorm.
 * User: Ari
 * Date: 8/1/13
 * Time: 8:40 PM
 * To change this template use File | Settings | File Templates.
 */

var DOMAIN = '/clevertree-bitcoin-casino';
var POLL_PATH = DOMAIN + '/poll';

var CLIENT_PORT = 7845;
var EVENT_PORT = 7844;
var EVENT_SOURCE = 'http://localhost:' + CLIENT_PORT;
var WEB_SOCKET_URL = 'ws://localhost:' + CLIENT_PORT;

var ABORT_DELAY = 500;

var PING_BUFFER = 1;
var PING_DELAY = 200;
var PING_ERROR_DELAY = 5000;
var COMMAND_POLL_START = 'poll-start';
var COMMAND_POLL_ABORT = 'poll-abort';
var COMMAND_ADD = 'add';
var COMMAND_PATH = 'path';
var COMMAND_ERROR = 'error';
var COMMAND_MESSAGE = 'msg';

var connections = 0; // count active connections
var activeURLs = [];
var queryCount = 0;
var timeout = 500;
var lastPingBuffer = null;
var currentRequests = [];

function doQuery() {
    if(activeURLs.length === 0) {
        self.postMessage([COMMAND_ERROR + " No active urls to query", 400]);
        throw new Error("No active urls to query");
    }
    if(currentRequests.length !== 0) {
        self.postMessage([COMMAND_ERROR + " Unfinished queries", 400]);
        throw new Error("Unfinished queries");
    }

    for (var i = 0; i < activeURLs.length; i++)
        (function(i) {
            try {
                var url = DOMAIN + '/' + activeURLs[i][0] + '?' + (new Date().getTime() / 1000 | 0);
                var offset = activeURLs[i][1];

                var headers = {
                    'Range': 'bytes=' + (offset > 0 ? offset - PING_BUFFER : 0) + '-' // + (offset + 1000)
                };
                currentRequests[currentRequests.length] = load(url, function (content, statusCode, xhr) {
                    for(var i=0; i<currentRequests.length; i++) {
                        if(currentRequests[i] === xhr) {
                            currentRequests.splice(i, 1);
                            break;
                        }
                    }
                    if (statusCode !== 200 && statusCode !== 206) {
                        //content = 'err Invalid Response Status Code: ' + statusCode;
                        timeout += PING_ERROR_DELAY;
                        self.postMessage(COMMAND_ERROR + " Invalid Response (" + statusCode + "): " + xhr.statusText);
                        if (currentRequests.length === 0)
                            setTimeout(doQuery, timeout);
                        throw new Error("Invalid Response (" + statusCode + "): " + content);
                    }

                    if (currentRequests.length === 0)
                        setTimeout(doQuery, timeout);

                    if(offset > 0) {
                        lastPingBuffer = content.substr(0, PING_BUFFER);
                        content = content.substr(PING_BUFFER);
                    }

                    if(content.length > 0) {
                        if(content.length === offset)
                            throw new Error("Offset matches content");

                        activeURLs[i][1] = offset + content.length;
                        self.postMessage(content);
                        timeout = PING_DELAY;
                    } else {
                        timeout += PING_DELAY;
                    }

                }, headers)
            } catch (err) {
                self.postMessage(COMMAND_ERROR + ' ' + err.message);

            }
        })(i);

}


var eventSource = null;
function getEventSourceURL() {
    var pollURL = EVENT_SOURCE + '?' + COMMAND_PATH + '=';
    for (var ii = 0; ii < activeURLs.length; ii++)
        pollURL += (ii?';':'') + activeURLs[ii][0] + "," + activeURLs[ii][1];
    return pollURL;
}

function doEventSource() {
    if(eventSource === null)
        eventSource = new EventSource(getEventSourceURL());

    var Self = self;

    eventSource.addEventListener('line', function (e) {
        if(this !== eventSource)
            throw new Error("Old Eventsource: " + eventSource);
        console.log(e);
        var line = e.data;
        Self.postMessage(line);

    }, false);

    eventSource.addEventListener('eof', function (e) {
        var args = e.data.split(':', 2);
        var path = args[0];
        var offset = parseInt(args[1]);
        console.log("Updated offset: " + offset + ' - ' + path);
        for(var ii=0; ii<activeURLs.length; ii++) {
            if(path === activeURLs[ii][0]) {
                activeURLs[ii][1] = offset;
            }
        }
        if(this !== eventSource)
            throw new Error("Old Eventsource: " + eventSource);
        //eventSource.close();
        //eventSource = null;
        //setTimeout(doEventSource, 500);
    }, false);

    eventSource.addEventListener('close', function (e) {
        console.log(e);
        Self.postMessage('msg close ' + e.data);
    }, false);

    eventSource.addEventListener('message', function (e) {
        console.log(e);
        Self.postMessage('msg ' + e.data);
    }, false);

    eventSource.addEventListener('error', function(e) {
        console.log(e);
        Self.postMessage('error ' + e.data);
    }, false);
}

function doLongPoll() {
    if(activeURLs.length === 0) {
        self.postMessage([COMMAND_ERROR + " No active urls to query", 400]);
        throw new Error("No active urls to query");
    }
    if(currentRequests.length !== 0) {
        self.postMessage([COMMAND_ERROR + " Unfinished queries", 400]);
        throw new Error("Unfinished queries");
    }

    var pollURL = POLL_PATH + '?' + COMMAND_PATH + '=';
    for (var ii = 0; ii < activeURLs.length; ii++)
        pollURL += (ii?';':'') + activeURLs[ii][0] + "," + activeURLs[ii][1];

    try {
        var headers = {
            'Accept': 'application/json'
        };
        currentRequests[currentRequests.length] = load(pollURL, function (content, statusCode, xhr) {
            for(var i=0; i<currentRequests.length; i++) {
                if(currentRequests[i] === xhr) {
                    currentRequests.splice(i, 1);
                    break;
                }
            }

            if(statusCode === 0)
                return;

            if (statusCode !== 200 && statusCode !== 206 && statusCode !== 400) {
                //content = 'err Invalid Response Status Code: ' + statusCode;
                timeout += PING_DELAY;
                if (currentRequests.length === 0)
                    setTimeout(doLongPoll, timeout);
                self.postMessage(COMMAND_ERROR + " Invalid Response (" + statusCode + "): " + xhr.statusText);
                throw new Error("Invalid Response (" + statusCode + "): " + content);
            }
            if (currentRequests.length === 0)
                setTimeout(doLongPoll, timeout);

            console.log(content);
            if(content.length > 0) {
                self.postMessage(content);

                var lines = content.split("\n");
                var found = false;
                for(i=0; i<lines.length; i++) {
                    var line = lines[i];
                    if(line.indexOf(COMMAND_PATH) === 0) {
                        var args = line.split(' ', 3);
                        var path = args[1];
                        var offset = parseInt(args[2]);
                        for(var ii=0; i<activeURLs.length; ii++) {
                            if(path === activeURLs[ii][0]) {
                                activeURLs[ii][1] = offset;
                                found = true;
                            }
                        }
                    }
                }
                if(!found)
                    throw new Error("Path not in list: " +content);

                timeout = PING_DELAY;
            } else {
                timeout += PING_DELAY;
            }

        }, headers)
    } catch (err) {
        self.postMessage(COMMAND_ERROR + err.message);
    }

}

var curCallback = doQuery;
var clearAddDelay = null;
self.addEventListener("message", function (e) {
    var args = e.data.split(' ');
    switch(args[0]) {
        case COMMAND_POLL_START:
            if(currentRequests.length === 0)
                curCallback();
            break;

        case COMMAND_POLL_ABORT:
            //for(var i=0; i<currentRequests.length; i++)
            //    currentRequests[i].abort();
            //currentRequests = [];
            //setTimeout(function() {
            //    doLongPoll();
            //}, ABORT_DELAY);

            break;
        case COMMAND_ADD:
            var url = args[1];
            var offset = parseInt(args[2]);
            activeURLs.push([url, offset]);
            if(clearAddDelay)
                clearTimeout(clearAddDelay);
            clearAddDelay = setTimeout(curCallback, 200);
            break;

        default:
            throw new Error("Unknown command: " + e.data);
    }
}, false);

//
//self.addEventListener("connect", function (e) {
//
//    //var port = e.ports[0];
//    connections++;
//
//    port.start();
//
//}, false);

//simple XHR request in pure JavaScript
function load(url, callback, headers) {
    var xhr;

    if(typeof XMLHttpRequest !== 'undefined') xhr = new XMLHttpRequest();
    else {
        var versions = ["MSXML2.XmlHttp.5.0",
            "MSXML2.XmlHttp.4.0",
            "MSXML2.XmlHttp.3.0",
            "MSXML2.XmlHttp.2.0",
            "Microsoft.XmlHttp"];

        for(var i = 0, len = versions.length; i < len; i++) {
            try {
                xhr = new ActiveXObject(versions[i]);
                break;
            }
            catch(e){}
        } // end for
    }

    xhr.onreadystatechange = ensureReadiness;

    function ensureReadiness() {
        if(xhr.readyState < 4)
            return;

        if(xhr.readyState !== 4) {
            callback("Invalid readyState: " + xhr.readyState, 0, xhr);
            return;
        }

        callback(xhr.response, xhr.status, xhr);
    }

    xhr.open('GET', url, true);
    if(typeof headers === 'object')
        for(var name in headers)
            if(headers.hasOwnProperty(name))
                xhr.setRequestHeader(name, headers[name]);
    xhr.send('');
    return xhr;
}

//var worker = new SharedWorker("jsworker.js");
//
//worker.port.addEventListener("message", function(e) {
//    alert(e.data);
//}, false);
//
//worker.port.start();
//
//// post a message to the shared web worker
//worker.port.postMessage("Alyssa");